﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.IO;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace Microsoft.CloudSaver.Web.Infrastructure
{
    public static class CloudUtils
    {

        private static CloudStorageAccount account;
        private static TableContext context;
       
        private static Random fileNumbers = new Random();

        static CloudUtils()
        {
            SetupPublisher();
            account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            context = new TableContext(account.TableEndpoint.ToString(), account.Credentials);            
        }
                
        #region Settings Management

        internal static string GetValue(string name)
        {
            return GetValue("cloudsaver", name);
        }

        //Specifing the partition it reads into the user-specific settings store
        internal static string GetValue(string partition, string name)
        {
            try
            {
                return context.Settings.Where(p => p.PartitionKey == partition.ToLower() && p.RowKey == name).First().Value;
            }
            catch (Exception)
            {
                return null;
            }

        }

        //Specifing the partition it writes into the user-specific settings store
        internal static void SetValue(string partition, string name, string value)
        {
            try
            {
                var item = context.Settings.Where(p => p.PartitionKey == partition.ToLower() && p.RowKey == name).First();
                item.Value = value;
                context.UpdateObject(item);
            }
            catch (Exception)
            {
                context.AddObject(TableContext.SettingsTable, new SettingsItem() { PartitionKey = partition.ToLower(), Name = name, Value = value });

            }
            context.SaveChanges();

        }

        internal static void SetValue(string name, string value)
        {
            SetValue("cloudsaver", name, value);

        }

        #endregion

        #region Blobs Management

        internal static void SaveBlob(string container, HttpPostedFile file, byte[] content)
        {
            //var cont = account.CreateCloudBlobClient().GetContainerReference(container.ToLower());
            //var blob = cont.GetBlobReference(new FileInfo(file.FileName).Name);
            //blob.Attributes.Properties.ContentType = file.ContentType;
            //blob.UploadByteArray(content);
            SaveBlob(container, file.ContentType, content, file.FileName);
        }

        internal static void SaveBlob(string container, string mimeType, byte[] content, string fileName)
        {
            var cont = account.CreateCloudBlobClient().GetContainerReference(container.ToLower());
            var blob = cont.GetBlobReference(new FileInfo(fileName).Name);
            blob.Attributes.Properties.ContentType = mimeType;
            blob.UploadByteArray(content);
        }

        internal static bool Exists(this CloudBlob blob)
        {
            try
            {
                blob.FetchAttributes();
                return true;
            }
            catch (StorageClientException e)
            {
                if (e.ErrorCode == StorageErrorCode.ResourceNotFound)
                {
                    return false;
                }
                else
                {
                    throw;
                }
            }
        }
        
        internal static void RemoveBlob(string container, string name)
        {
            var cont = account.CreateCloudBlobClient().GetContainerReference(container.ToLower());
            var blob = cont.GetBlobReference(name);
            blob.DeleteIfExists();
        }
        
        //Downloads locally the blob to send it through reponse
        internal static string GetLocalFileReference(string container, string name)
        {
            SetupPersonalFolder(container);
            LocalResource local = RoleEnvironment.GetLocalResource("TempStorage");
            var blob = account.CreateCloudBlobClient().GetContainerReference(container.ToLower()).GetBlobReference(name);
            string fileName = Path.Combine(local.RootPath, container.ToLower(), fileNumbers.Next(int.MaxValue).ToString());
            blob.DownloadToFile(fileName);
            return fileName;
        }
                
        internal static IEnumerable<dynamic> ListBlobs(string container)
        {
            var client = account.CreateCloudBlobClient();
            var blobs = client.GetContainerReference(container.ToLower()).ListBlobs();
            foreach (var item in blobs)
            {
                var blob = client.GetBlobReference(item.Uri.AbsoluteUri);
                blob.FetchAttributes();
                yield return new
                {
                    Name = blob.Uri.Name(),
                    Size = (((int)(blob.Properties.Length / 1024)) + 1).ToString() + "KB",
                    Type = blob.Properties.ContentType,
                    Uri = blob.Uri.ToString()
                };
            }
        }
        
        #endregion

        #region Utilities

        //Get the public url of the uploaded (or default) company logo
        internal static string GetCompanyLogoUrl()
        {
            return account.CreateCloudBlobClient().GetContainerReference("$root").GetBlobReference("companyLogo.png").Uri.ToString();
        }
        
        //It checks the format of the logo and upload it into the blob storage, replacing the old one.
        internal static bool CheckAndUploadCompanyLogo(HttpPostedFile file, byte[] content)
        {
            try
            {
                System.Drawing.Image img = System.Drawing.Image.FromStream(file.InputStream);
                if (img.Width > 230 || img.Height > 60) return false;
            }
            catch { return false; }
            var image = account.CreateCloudBlobClient().GetContainerReference("$root").GetBlobReference("companyLogo.png");
            image.UploadByteArray(content);            
            return true;
        }

        //With IIS Full in Azure we need to setup the publisher also in the web application
        internal static void SetupPublisher()
        {
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });
        }

        #endregion

        #region Extensions

        internal static string Name(this Uri self)
        {
            if (self.ToString().Contains('/')) return self.ToString().Substring(self.ToString().LastIndexOf("/") + 1);
            else return self.ToString().Substring(self.ToString().LastIndexOf(@"\") + 1);
        }


        #endregion

        #region Initialization
        
        //It creates the default credentials
        internal static void CreateDefaultCredentials()
        {
            if (!System.Web.Security.Roles.RoleExists("User"))
            {
                System.Web.Security.Roles.CreateRole("User");
            }

            if (!System.Web.Security.Roles.RoleExists("Admin"))
            {
                System.Web.Security.Roles.CreateRole("Admin");
                if (System.Web.Security.Membership.FindUsersByName("admin").Count == 0)
                {
                    System.Web.Security.Membership.CreateUser("admin", "Passw0rd!", "cloudsaver@microsoft.com");
                    System.Web.Security.Roles.AddUsersToRole(new[] { "admin" }, "Admin");
                    CloudUtils.SetValue("admin", "Area", "Undefined");
                }
            }


        }

        //It creates the default containers
        internal static void CreateBlobContainers()
        {
            var root = account.CreateCloudBlobClient().GetContainerReference("$root");
            if (root.CreateIfNotExist())
            {
                root.SetPermissions(new BlobContainerPermissions() { PublicAccess = BlobContainerPublicAccessType.Blob });
            }
        }

        //It creates the default tables
        internal static void CreateCloudTables()
        {
            var cloudTableClient = account.CreateCloudTableClient();
            if (cloudTableClient.CreateTableIfNotExist(TableContext.SettingsTable))
            {
                CloudUtils.SetValue("CompanyName", "La mia azienda");
                CloudUtils.SetValue("CompanyUrl", "http://www.contoso.com");
            }
        }

        //It creates the default personal folder
        internal static void SetupPersonalFolder(string container)
        {
            LocalResource local = RoleEnvironment.GetLocalResource("TempStorage");
            var cont = account.CreateCloudBlobClient().GetContainerReference(container.ToLower());
            cont.CreateIfNotExist();
            var info = new DirectoryInfo(Path.Combine(local.RootPath, container.ToLower()));
            if (!info.Exists) info.Create();
            info.EnumerateFiles().ToList().ForEach(p => File.Delete(p.FullName));
            if (GetValue(container, "Theme") == null) SetValue(container, "Theme", "default");
            if (GetValue(container, "Area") == null) SetValue(container, "Area", "Undefined");
        }

        //It creates the default blobs
        internal static void SetupDefaultBlobs()
        {
            var image = account.CreateCloudBlobClient().GetContainerReference("$root").GetBlobReference("companyLogo.png");
            if (!image.Exists())
            {
                image.UploadFile(HttpContext.Current.Server.MapPath("~/Objects/Images/companyLogo.png"));
            }
        }
        
        #endregion
        
    }
}